home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
005
/
vol6n12.arc
/
REMINDER.ASM
next >
Wrap
Assembly Source File
|
1987-03-31
|
41KB
|
880 lines
; REMINDER.ASM
; Resident clock pop-up utility with hourly bell and appointment chime.
; REMINDER [foreground color],[border color],[scan code of hot key],
; [hourly tone frequency],[alarm tone frequency]
CODE SEGMENT ;*************************
ASSUME CS:CODE,DS:CODE ;* *
ORG 100H ;* REMEMBER TO EXE2BIN *
;* *
START: JMP INITIALIZE ;*************************
; DATA AREA
; ---------
COPYRIGHT DB 'Copyright 1987 Ziff-Davis Publishing Co.',1AH
PROGRAMMER DB 'Michael J. Mefford'
OLD_TIMER DD ?
OLD_KEYBOARD DD ?
OLD_CURSPOS DW ?
CURSOR_TYPE DW ?
CURSPOS DW 325H
STATUS_REG DW ?
SCREEN_SEG DW 0B000H
TIMER_HIGH DW ?
LAST_HOUR DW ?
BELL_COUNT DB 0
HERTZ DW ?
BUSY DB 0
DISPLAY_FLAG DB 1
ALARM_FLAG DB 1
MATCH_FLAG DB 0
POPUP_FLAG DB 0
VIDEO_FLAG DB 0
FOREGROUND DW 07H
BORDER DW 70H
HOT_KEY DW 19
HOURLY_FREQ DW 2217
ALARM_FREQ DW 2960
DISPATCH_KEY DB 59,60,61,62,71,72,75,77,79,80
DISPATCH_TABLE DW OFFSET ERASE , OFFSET ALARM_ABLE
DW OFFSET INSERT , OFFSET DISPLAY_ABLE
DW OFFSET HOME_KEY , OFFSET CURS_UP
DW OFFSET CURS_LEFT , OFFSET CURS_RIGHT
DW OFFSET END_KEY , OFFSET CURS_DOWN
SKIP DB 39,42,44,45,46
DIS DB 'Dis'
EN DB ' En'
WEEKDAY DB 'SunMonTueWedThuFriSat'
;************* KEYBOARD INTERCEPTOR ************;
;-----------------------------------------------------------------;
; Let BIOS get the keystroke then see if we should pop up window. ;
;-----------------------------------------------------------------;
NEW_KEYBOARD: STI ;Turn interrupts back on
PUSHF ;Simulate an interrupt
CALL CS:OLD_KEYBOARD ; by pushing flags and far call.
PUSHF ;On return save all registers
PUSH DS ; that will be used.
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
PUSH CS ;Point to our data.
POP DS
CLD ;Moves in forward direction.
CMP BUSY,0 ;If the window is already popped
JNZ DONE_HERE ; exit Int 9 back to window.
CMP VIDEO_FLAG,1 ;If graphics mode, exit.
JZ DONE_HERE
CMP POPUP_FLAG,1 ;If event happened, pop up.
JZ OPEN_WINDOW
MOV AH,1 ;Is an ASCII character ready?
INT 16H
JZ DONE_HERE ;If it's just a key release, exit.
CMP AL,0 ;Is it extended code?
JNZ DONE_HERE ;If no, exit.
CMP AH,BYTE PTR HOT_KEY ;Else, see if our key combo.
JZ OPEN_WINDOW ;If yes, open window
DONE_HERE: JMP EXIT_KEYBOARD ; else exit.
;------------------------------------------------------------------------;
; Save screen so we can pop up REMINDER. Save cursor position and mode. ;
;------------------------------------------------------------------------;
OPEN_WINDOW: OR BUSY,1 ;Flag that window is open.
XOR DISPLAY_FLAG,2 ;Enable time display.
MOV AH,0 ;Retrieve and discard hot key
INT 16H ; character from keyboard buffer.
CALL STORE_SCREEN ;Store screen.
XOR BH,BH
MOV AH,3
INT 10H ;Retrieve
MOV OLD_CURSPOS,DX ; cursor mode and save.
MOV CX,0B0CH ;Assume monocard underscore cursor
CMP STATUS_REG,3BAH ;Confirm via status register.
JZ MONO_CURSOR ;If yes, change cursor.
MOV CX,0607H ;Else, assume color card cursor
MONO_CURSOR: MOV CURSOR_TYPE,CX
MOV AH,1 ; and set cursor type.
INT 10H
;-------------------------------------------;
; This is the main loop. The keyboard will ;
; be monitored and appropriate subroutines ;
; will service the proper key responses. ;
;-------------------------------------------;
;***********;
; MAIN LOOP ;
;***********;
READ_KEY: MOV SI,OFFSET WINDOW ;Update our window.
CALL POP_UP
CALL SET_CURSPOS ;Update cursor position.
MOV AH,0 ;Wait for an ASCII character.
INT 16H
CMP AL,27 ;Is it Esc?
JZ EXIT_WINDOW
CMP AL,13 ;Is it carriage return?
JNZ CK_BS
CALL CR
JMP SHORT READ_KEY
CK_BS: CMP AL,8 ;Is it backspace?
JNZ CK_ASCII
CALL BS
JMP SHORT READ_KEY
CK_ASCII: CMP AL,0 ;Is it an extended scan code?
JNZ ASCII ;If no, it's ASCII
CMP AH,BYTE PTR HOT_KEY ;Is it our key combo?
JZ EXIT_WINDOW ;If yes, exit window.
MOV CX,10 ;Check for a match with
MOV DI,OFFSET DISPATCH_KEY ; one of the twelve extended
XCHG AH,AL ; codes from our dispatch table.
REPNZ SCASB
JNZ READ_KEY ;If no match, next key.
MOV DI,OFFSET DISPATCH_TABLE+18 ;point to end of offsets.
SHL CX,1 ;Double count.
SUB DI,CX ;Subtract to get offset.
CALL DS:[DI] ;Call the subroutine.
JMP SHORT READ_KEY ;Then return for next key.
ASCII: MOV BX,CURSPOS ;Retrieve cursor position.
CMP BL,78 ;Is it in last column?
JZ READ_KEY ;If yes, skip.
CMP AL,32 ;Is it space?
JZ STORE_ASCII ;If yes, store.
JB READ_KEY ;If below, skip.
CMP BL,43 ;Is it AM/PM column?
JNZ STORE_ASCII ;If no, store.
AND AL,5FH ;Else, capitalize.
CMP AL,'A' ;Check to see if A or P.
JZ STORE_ASCII
CMP AL,'P'
JNZ READ_KEY
STORE_ASCII: CALL STORE_CHAR
MOV BX,1 ;Increment cursor position.
CALL MOVE_CURSOR
JMP SHORT READ_KEY
;***************;
; END MAIN LOOP ;
;***************;
;------------------------------------;
; This is the keyboard exit routine. ;
;------------------------------------;
EXIT_WINDOW: XOR DISPLAY_FLAG,2 ;Restore the time display state.
MOV SI,OFFSET SCREEN ;Point to the stored screen
CALL POP_UP ; and restore the screen.
MOV DX,OLD_CURSPOS ;Retrieve old cursor postion
CALL ROW_COLUMN ; and restore.
MOV CX,CURSOR_TYPE ;Retrieve old cursor type
MOV AH,1 ; and restore.
INT 10H
AND POPUP_FLAG,0 ;Restore pop up flag.
AND BUSY,0 ;Flag done with window.
EXIT_KEYBOARD: POP BP ;Restore all registers.
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POPF
IRET ;Return from interrupt.
;--------------------------------------;
; This subroutine retrieves and stores ;
; the upper right corner of screen. ;
;--------------------------------------;
STORE_SCREEN: MOV DX,STATUS_REG ;Retrieve the status register.
MOV AX,SCREEN_SEG ;Point to screen segment.
MOV DS,AX
PUSH CS
POP ES
MOV SI,70 ;Point to start of window.
MOV DI,OFFSET SCREEN ;Point to storage.
MOV BX,17 ;17 rows to save.
READ_SCREEN: MOV CX,45 ;45 characters per row.
HORZ_RET1: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET1 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT1: IN AL,DX ;Get status
TEST AL,1 ;Is it high?
JZ WAIT1 ;If no, wait until it is.
LODSW ;Retrieve a word.
STI ;Interrupts back on.
STOSW ;Store the character/attribute.
LOOP HORZ_RET1 ;Get next byte.
ADD SI,70 ;Point to next row
DEC BX
JNZ READ_SCREEN
PUSH CS ;Restore data segment.
POP DS
RET ;Return.
;-------------------------------------------------;
; This subroutine controls the position we write ;
; to the screen and the number of rows we write. ;
;-------------------------------------------------;
POP_UP: MOV DI,70 ;Starting column 70/2 = 35
MOV BP,17 ;17 rows to write.
NEXT_ROW1: MOV CX,45 ;45 characters per row.
CALL WRITE_SCREEN
ADD DI,70 ;Increment to next row.
DEC BP
JNZ NEXT_ROW1
RET
;---------------------------------------------;
; This subroutine writes to the screen buffer ;
;---------------------------------------------;
WRITE_SCREEN: MOV DX,STATUS_REG ;Retrieve status register
MOV AX,SCREEN_SEG ;Point to the screen buffer.
MOV ES,AX
PUT_BYTE: LODSW ;Get a byte.
MOV BX,AX ;Store it in AX.
HORZ_RET2: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET2 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT2: IN AL,DX ;Get status.
TEST AL,1 ;Is it high?
JZ WAIT2 ;If no, wait until it is.
MOV AX,BX ;Retrieve the word
STOSW ; and store it.
STI ;Interrupts back on.
LOOP PUT_BYTE ;Write next character/attribute.
PUSH CS
POP ES
RET
;-----------------------------------------------------;
; This subroutine stores what is typed in the window. ;
;-----------------------------------------------------;
STORE_CHAR: MOV BX,CURSPOS ;Retrieve cursor position.
MOV CL,AL ;Save character.
MOV AX,90 ;90 characters per row.
MUL BH ;Times cursor row.
SUB BL,35 ;Adjust column.
SHL BL,1 ;Double for attributes.
XOR BH,BH
ADD BX,AX ;Add column/row for offset.
ADD BX,OFFSET WINDOW ;Add window offset.
MOV [BX],CL ;Store the character.
RET
;-----------------------------------------------------;
; These subroutines move and set the cursor position. ;
;-----------------------------------------------------;
MOVE_CURSOR: MOV AX,CURSPOS ;Retrieve current position.
ADD AH,BH ;Add requested row move.
NEXT_MOVE: ADD AL,BL ;Add requested column move.
MOV CX,5 ;Check restricted columns.
MOV DI,OFFSET SKIP ;Point to table.
REPNZ SCASB
JZ NEXT_MOVE ;If off limits move another.
MOV CURSPOS,AX ;Store new position.
CALL SET_CURSPOS ;Move cursor.
RET
SET_CURSPOS: MOV DX,CURSPOS
ROW_COLUMN: XOR BH,BH ;Page zero.
MOV AH,2 ;Move cursor via BIOS.
INT 10H
RET
;------------------------------------------------------;
; These subroutines control the movement of the cursor ;
;------------------------------------------------------;
CURS_RIGHT: MOV BX,1 ;Plus one column to move.
CMP DL,78 ;Already far right column?
JNZ END_CURSOR ;If no, move it.
RET
CURS_LEFT: MOV BX,0FFH ;Minus one column to move.
CMP DL,37 ;Already far left column?
JNZ END_CURSOR ;If no, move it.
RET
CURS_UP: MOV BX,0FF00H ;Minus one row to move.
CMP DH,3 ;Is it already top?
JNZ END_CURSOR ;If no, move it.
RET
CURS_DOWN: MOV BX,100H ;Plus one row to move.
CMP DH,12 ;Is it already bottom?
JNZ END_CURSOR ;If no, move it.
RET
BS: CMP DL,37 ;Is it already far left?
JZ BS_RETURN ;If yes, skip.
MOV BX,0FFH ;Else, minus one column to move.
CALL MOVE_CURSOR ;Move it.
MOV AL,32 ;Store space in that position.
CALL STORE_CHAR
BS_RETURN: RET
CR: MOV BYTE PTR CURSPOS,37 ;Move cursor to first column.
MOV BX,100H ;Plus one row to move.
CMP DH,12 ;Already at bottom?
JNZ END_CURSOR ;If no, move it.
MOV BX,0 ;Else, zero row move.
END_CURSOR: CALL MOVE_CURSOR
RET
;---------------------------------------------------;
HOME_KEY: MOV BYTE PTR CURSPOS,37 ;Move to first column.
JMP SHORT END_POSITION
END_KEY: MOV BYTE PTR CURSPOS,78 ;Move to last column.
END_POSITION: CALL SET_CURSPOS
RET
;---------------------------------------------------;
; These subroutines delete a line or insert a line. ;
;---------------------------------------------------;
ERASE: CALL GET_COUNT ;Prepare for moving lines.
JZ BLANK_LINE ;Skip if zero lines to move.
MOV SI,DI
ADD SI,90
REP MOVSB ;Else, move the lines up
JMP SHORT BLANK_LINE ;Blank out bottom line.
INSERT: CALL GET_COUNT ;Prepare for moving lines.
JZ BLANK_LINE ;Skip if zero lines to move.
MOV SI,OFFSET WINDOW+90*12-2
MOV DI,OFFSET WINDOW+90*13-2
STD
REP MOVSB ;Else, move the lines down.
CLD
SUB DI,88 ;Adjust pointer.
BLANK_LINE: MOV AL,32 ;Blank the line with space
MOV AH,BYTE PTR FOREGROUND ;and foreground color.
INC DI
INC DI
MOV CX,43 ;43 characters.
REP STOSW
MOV BYTE PTR DS:[DI-80],':' ;Restore the delimiter
MOV BYTE PTR DS:[DI-70],'M' ; characters
MOV BYTE PTR CURSPOS,37 ; and move the cursor.
RET
GET_COUNT: MOV CX,90*12 ;Assume last row.
MOV DL,BYTE PTR CURSPOS+1 ;Retrieve cursor row.
MOV AX,90 ;Times 90 characters per row.
MUL DL
MOV DI,OFFSET WINDOW ;Point to start of window entries
ADD DI,AX ;Add offset of row and subtract
SUB CX,AX ; to get characters to move.
RET
;--------------------------------------------------------------;
; These subroutines toggle either the alarm or display status. ;
;--------------------------------------------------------------;
ALARM_ABLE: MOV AX,TIMER_HIGH ;Update last hour so hourly
MOV LAST_HOUR,AX ; alarm will not go off
MOV DI,OFFSET WINDOW+(14*90)+70 ; if toggled on.
XOR ALARM_FLAG,1 ;Toggle alarm flag.
CMP ALARM_FLAG,0 ;Set carry flag to indicate
JMP SHORT SHOW_ABLE ; status and display.
DISPLAY_ABLE: XOR DISPLAY_FLAG,1 ;Toggle display flag
CMP DISPLAY_FLAG,2 ;Set carry flag.
JNZ SHOW_TIME
MOV AH,SCREEN+47 ;Use the attribute next door
MOV AL,32 ; with space to clear time
MOV DI,OFFSET SCREEN+48 ; from screen data.
MOV CX,21
REP STOSW
SHOW_TIME: MOV DI,OFFSET WINDOW+(15*90)+70
CMP DISPLAY_FLAG,2
SHOW_ABLE: MOV SI,OFFSET DIS ;If flag zero
JZ SHOW_THIS ; show "Disable"
MOV SI,OFFSET EN ; else show "Enable"
SHOW_THIS: MOV CX,3 ;Move the three bytes
SHOW_STORE: MOVSB ; into the window.
INC DI ;Bump past attribute.
LOOP SHOW_STORE
RET
;************* TIMER INTERCEPTOR *************;
NEW_TIMER: STI ;Interrupts back on
PUSHF ; and save all registers
PUSH DS ; that we will use.
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
;-----------------------------------;
; Retrieve the video mode and time. ;
;-----------------------------------;
CLD ;String moves in forward direction
PUSH CS ;Point to our data.
POP DS
MOV AX,40H ;Point to BIOS data.
MOV ES,AX
MOV AL,ES:[49H] ;Retrieve video mode.
MOV CL,0 ;Assume text mode.
CMP AL,2 ;Is it graphics or 40 column?
JZ STORE_MODE ;If no, flag as OK.
CMP AL,3
JZ STORE_MODE
CMP AL,7
JZ STORE_MODE
MOV CL,1 ;Else, flag as not OK.
STORE_MODE: MOV VIDEO_FLAG,CL
MOV CX,ES:[6CH] ;Retrieve timer low
MOV AX,ES:[6EH] ; and timer high.
MOV TIMER_HIGH,AX
PUSH CS ;Restore extra segment.
POP ES
;---------------------------------------;
; Convert the timer to 12 hour meridian ;
; format and store in the window. ;
;---------------------------------------;
MOV BL,'A' ;Assume AM
CMP AX,24 ;If midnight display AM
JE DISPLAY_MUNDI
CMP AX,11 ;If before noon display AM
JBE DISPLAY_MUNDI
MOV BL,'P' ;Else, display PM.
DISPLAY_MUNDI: MOV DI,OFFSET WINDOW+86
CMP AX,12 ;Adjust if over 12.
JBE DISPLAY_HOUR
SUB AX,12
DISPLAY_HOUR: MOV [DI],BL ;Store either the "A" or "P".
SUB DI,12 ;Point to hour.
MOV BH,1 ;Supress leading zero.
CALL STORE_NUMBER ;Store hour.
MOV AX,CX ;Retrieve timer low.
XOR DX,DX
MOV CX,1093 ;And divide by 1093 counts
DIV CX ; per minute.
MOV BH,0 ;Don't suppress leading zero.
MOV CL,WINDOW+82 ;Retrieve current minute.
CALL STORE_NUMBER ;Store new minute.
CMP AL,CL ;Check if one minute has gone by.
JZ TIME_DONE ;If no, skip.
MOV MATCH_FLAG,0 ;If yes, reset match flag.
;---------------------------------------------------;
; Display time unless disabled or in graphics mode. ;
;---------------------------------------------------;
TIME_DONE: CMP DISPLAY_FLAG,0 ;Skip display if display flag low
JZ CK_MATCH
CMP VIDEO_FLAG,1 ;Skip also if in graphics mode.
JZ CK_MATCH
DISPLAY_TIME: MOV SI,OFFSET WINDOW+48 ;Point to date and time.
MOV DI,2*59 ;Point to top left of screen.
MOV CX,21 ;Display the 21 characters of
CALL WRITE_SCREEN ; date and time.
;----------------------------------------;
; Compare the current date and time with ;
; alarm date and time fields in window. ;
;----------------------------------------;
CK_MATCH: CMP MATCH_FLAG,2
JZ GOT_MATCH
MOV AX,10 ;Check the 10 possible time
MOV BX,OFFSET WINDOW+274 ; entry fields of time with
COMP_TIME: MOV DI,OFFSET WINDOW+74 ; the current time.
MOV SI,BX
MOV CX,7 ;There are 7 bytes in time field.
REPZ CMPSW
JZ MATCH ;If match, alarm.
ADD BX,90
DEC AX
JNZ COMP_TIME
;-------------------------------------;
; If we didn't get a match with event ;
; alarm, see if the hour has changed. ;
;-------------------------------------;
HOURLY_ALARM: CMP ALARM_FLAG,0 ;Skip if hourly alarm is disabled
JZ EXIT_TIMER
MOV AX,TIMER_HIGH ;Else, see if hour has changed
CMP AX,LAST_HOUR
JZ EXIT_TIMER ;If no, exit
MOV BX,HOURLY_FREQ ;Else, ring hourly alarm.
CALL BELL
JMP SHORT EXIT_TIMER ;And exit.
;-----------------------------------------;
; If we have a match, ring message alarm. ;
;-----------------------------------------;
MATCH: CMP MATCH_FLAG,0 ;Is the message alarm done?
JNZ EXIT_TIMER ;If yes, exit
NEG AX ;Else, subtract match count
ADD AX,13 ; from 13 to get cursor row.
XCHG AH,AL
MOV AL,37 ;First column.
MOV CURSPOS,AX ;Point to matching event.
MOV POPUP_FLAG,1 ;Flag so will pop up when able.
MOV MATCH_FLAG,2
GOT_MATCH: MOV BX,ALARM_FREQ ;Ring event alarm.
CALL BELL
EXIT_TIMER: POP DI ;Restore registers
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POPF
JMP CS:OLD_TIMER ;And service old timer interrupt.
;--------------------------------------------------------------;
; This subroutine turns the speaker on and off for the alarms. ;
;--------------------------------------------------------------;
BELL: CMP BELL_COUNT,14*2 ;Toggle the speaker on and off
JNZ START_BELL ; 14 times.
IN AL,61H ;Get timer port
AND AL,11111100B ; and mask off speaker bits.
OUT 61H,AL
MOV BELL_COUNT,0 ;Reset bell counter.
MOV AX,TIMER_HIGH ;Update hour flag.
MOV LAST_HOUR,AX
MOV MATCH_FLAG,1 ;Turn off match flag for one min.
RET ;Return.
START_BELL: CMP BELL_COUNT,0 ;Is this first time through?
JNZ TOGGLE_BELL ;If yes, toggle the bell
MOV AL,10110110B ;Else, initialize the 8253.
OUT 43H,AL
MOV DX,12H ;Divide 120000H by divisor.
XOR AX,AX
DIV BX
OUT 42H,AL ;Send divisor to chip.
MOV AL,AH
OUT 42H,AL
IN AL,61H
AND AL,11111100B ;Mask off speaker bits.
OUT 61H,AL
TOGGLE_BELL: IN AL,61H ;Get port 61h
XOR AL,00000011B ;Toggle speaker.
OUT 61H,AL
INC BELL_COUNT ;Increment bell count.
RET
;------------------------------------------------;
; This subroutine converts the number to decimal ;
; ASCII. Leading zero suppression is checked. ;
;------------------------------------------------;
STORE_NUMBER: MOV BL,10 ;Divide by ten.
DIV BL
ADD AX,'00' ;Convert to ASCII.
CMP BH,0 ;Suppress leading zero?
JZ STORE_IT ;If no, store it.
CMP AL,'0' ;Else, is it leading zero?
JNZ STORE_IT ;If no, store it.
MOV AL,32 ;Else store a space character.
STORE_IT: STOSB
XCHG AH,AL ;Retrieve the remainder.
INC DI ;Bump past attribute.
STOSB ;Store it.
ADD DI,3 ;Point to next position.
RET
;----------------------------------------------------------------------;
; This is the end of the resident code. Everything below is not needed ;
; after initialization so we will use the space for window storage. ;
;----------------------------------------------------------------------;
SCREEN LABEL BYTE
WINDOW EQU SCREEN+45*2*17
END_RESIDENT EQU WINDOW+45*2*17
;************* INITIALIZATION *************;
;-------------------------------;
; Get the parameters and store. ;
;-------------------------------;
INITIALIZE: CLD
CMP BYTE PTR DS:[80H],0 ;Any parameters?
JZ SETUP_WINDOW ;If no, skip.
MOV SI,82H ;Else, point to parameters.
MOV DI,OFFSET FOREGROUND ;Point to variables.
MOV CX,5 ;Five variables.
NEXT_PARSE: CMP BYTE PTR [SI-1],13 ;Carriage return?
JZ SETUP_WINDOW ;If yes, done here.
CMP BYTE PTR [SI],',' ;Delimiter?
JNZ GET_IT ;If no, get parameter.
INC SI ;Else, bump past comma.
JMP SHORT NEXT_PARA ;Get next parameter.
GET_IT: CALL GET_PARA
MOV DS:[DI],BX ;Store parameter in variable.
NEXT_PARA: INC DI ;Point to next variable.
INC DI
LOOP NEXT_PARSE
;---------------------------------------------------------------;
; To keep the program to its smallest possible size, the window ;
; has been conpressed. This routine uncompresses the data. ;
;---------------------------------------------------------------;
SETUP_WINDOW: MOV AL,32 ;Fill window with space
MOV AH,BYTE PTR BORDER ; and border color.
MOV BX,OFFSET WINDOW
MOV DI,BX
MOV CX,45*17 ;45 columns X 17 rows.
REP STOSW
MOV AL,205 ;Double line character.
MOV DI,OFFSET WINDOW+90+2 ;Top line.
CALL STORE_LINE
MOV DI,OFFSET WINDOW+(90*13)+2 ;Middle line.
CALL STORE_LINE
MOV DI,OFFSET WINDOW+(90*16)+2 ;Bottom line.
CALL STORE_LINE
MOV SI,OFFSET TEXT ;Point to text.
MOV CX,5 ;Placement of 5 text strings.
STORE_TEXT: LODSW ;Get offset.
MOV DI,AX
ADD DI,BX ;Add window offset.
NEXT_TEXT: LODSB ;Get character.
CMP AL,0 ;Is it the end?
JZ END_TEXT
STOSB ;If no, store character.
INC DI ;Bump past attribute.
JMP SHORT NEXT_TEXT
END_TEXT: LOOP STORE_TEXT
MOV CX,12 ;Placement of 12 characters.
STORE_BYTE: LODSW ;Get offset.
MOV DI,AX
ADD DI,BX ;Add window offset.
MOVSB ;Store it.
LOOP STORE_BYTE
MOV DH,4 ;Placement of 4 columns of chars.
STORE_MIDDLE: LODSW ;Get offset.
MOV DI,AX
ADD DI,BX ;Add window offset.
LODSB ;Get character.
MOV CX,10 ;Ten rows to place.
NEXT_MIDDLE: STOSB ;Store it.
ADD DI,89 ;Next row.
LOOP NEXT_MIDDLE
DEC DH
JNZ STORE_MIDDLE
;---------------------------------------------------------;
; This routine places the foreground color in the window. ;
;---------------------------------------------------------;
MOV AL,BYTE PTR FOREGROUND
MOV DI,OFFSET WINDOW+1 ;Point to top row.
MOV CX,45 ;45 attributes.
TOP_ROW: STOSB ;Store it.
INC DI ;Bump past character byte.
LOOP TOP_ROW
MOV BH,11 ;11 rows.
MOV DI,OFFSET WINDOW+(90*2)+3 ;Point to middle of window.
NEXT_ROW2: CALL STORE_LINE ;Store a line.
ADD DI,4 ;Next row.
DEC BH
JNZ NEXT_ROW2
MOV CX,2 ;2 rows.
MOV DI,OFFSET WINDOW+(90*14)+5 ;Point to "F1".
NEXT_FUNCT: STOSB ;Store two attributes.
INC DI
STOSB
ADD DI,31 ;Point to "F2".
STOSB ;Store two attributes.
INC DI
STOSB
MOV DI,OFFSET WINDOW+(90*15)+5 ;Next row.
LOOP NEXT_FUNCT
CALL UPDATE_DAY ;Place date in window.
;----------------------------------------------------------------------;
; We need the current hour, screen buffer segment and status register. ;
;----------------------------------------------------------------------;
CARD: MOV AX,40H ;Point to ROM BIOS data area
MOV ES,AX
MOV AX,ES:[6EH] ;Initialize current hour so alarm
MOV LAST_HOUR,AX ; won't ring upon install.
MOV AX,ES:[63H] ;Get base address of video card.
ADD AX,6 ;Convert to status register
MOV STATUS_REG,AX ; and store.
CMP AX,3BAH ;Is it mono card?
JZ INTERRUPT ;If yes, go to interrupt
ADD SCREEN_SEG,800H ; else point to color card.
;----------------------------------------------------------------;
; Ready to install. We will take keyboard and timer interrupts. ;
;----------------------------------------------------------------;
INTERRUPT: MOV AX,3509h ;Get keyboard interrupt.
INT 21H
MOV WORD PTR OLD_KEYBOARD,BX ;Save old interrupt.
MOV WORD PTR OLD_KEYBOARD[2],ES
MOV DX,OFFSET NEW_KEYBOARD ;Install new interrupt.
MOV AX,2509h
INT 21H
MOV AX,351CH ;Get timer tick vector
INT 21H
MOV WORD PTR OLD_TIMER,BX ; and store offset
MOV WORD PTR OLD_TIMER[2],ES ; and segment.
MOV DX,OFFSET NEW_TIMER ;Replace with our
MOV AX,251CH ; offset and segment.
INT 21H
MOV DX,OFFSET END_RESIDENT+1 ;Terminate but stay resident
INT 27H
;------------------------------------------------------------------;
; This subroutine gets the current date and puts it in the window. ;
;------------------------------------------------------------------;
UPDATE_DAY: MOV AH,2AH ;Get the date from DOS.
INT 21H
PUSH AX ;Save day of week.
MOV AL,DH ;Retrieve month.
XOR AH,AH
MOV DI,OFFSET WINDOW+48 ;Point to storage.
MOV BH,1 ;Suppress leading zero.
CALL STORE_NUMBER ;Store it.
MOV AL,DL ;Retrieve day.
XOR AH,AH
MOV BH,0 ;Store leading zero.
CALL STORE_NUMBER
MOV AX,CX ;Retrieve year.
SUB AX,1900 ;Throw away the century half
CMP AX,100 ; of year; if still over one
JB NOT_2000 ; hundred, subtract 100 for turn
SUB AX,100
NOT_2000: CALL STORE_NUMBER ; of century. (planning far ahead)
POP AX ;Retrieve day of week.
MOV CL,3 ;Point to the appropriate
MUL CL ; three character weekday
MOV SI,OFFSET WEEKDAY ; and move into window.
ADD SI,AX
MOV CX,3
NEXT_WEEKDAY: MOVSB
INC DI ;Bump past attribute.
LOOP NEXT_WEEKDAY
RET
;----------------------------------------------;
; This subroutine stores a line of attributes. ;
;----------------------------------------------;
STORE_LINE: MOV CX,43 ;43 attributes.
NEXT_LINE1: STOSB
INC DI ;Bump past character.
LOOP NEXT_LINE1
RET
;-----------------------------------------------------------;
; This subroutine converts a command line parameter to hex. ;
;-----------------------------------------------------------;
GET_PARA: XOR BX,BX ;Start with zero.
NEXT_DECIMAL: LODSB ;Get a character.
CMP AL,',' ;Delimiter?
JBE END_DECIMAL ;If yes, done.
SUB AL,30H ;Convert to hex.
XOR AH,AH
MOV BP,AX ;Save it in BP.
MOV AX,10
XOR DX,DX ;Shift to left by multiplying
MUL BX ; last pass by ten.
MOV BX,AX ;Save in BX.
ADD BX,BP ;Add new number.
JMP SHORT NEXT_DECIMAL
END_DECIMAL: MOV AX,BX ;Number in AX
RET
;--------------------------------------------------;
; Compressed data and offsets for window structure ;
;--------------------------------------------------;
TEXT DB 10,0,'Reminder',0,184,0,'Time',0,204,0,'Appointment',0
DB 236,4,186,' F1 Delete Line F2 Hourly Alarm Enabled ',186,0
DB 70, 5,186,' F3 Insert Line F4 Time Display Enabled ',186,0
DB 52,0,'-',58,0,'-',78,0,':',88,0,'M',90,0,201,178,0,187
DB 180,0,186,12,1,186,146,4,204
DB 234,4,185,160,5,200,248,5,188,14,1,186,22,1,':',32,1,'M',102,1,186
CODE ENDS
END START